/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package com.gaib.dmc;

import static com.gaib.dmc.GaIBReviewer_Ali.LoadModel;
import java.io.IOException;
import java.io.InputStream;
import java.util.List;
import java.util.logging.Level;
import java.util.logging.Logger;
import weka.classifiers.Classifier;
import weka.classifiers.UpdateableClassifier;
import weka.core.Attribute;
import weka.core.FastVector;
import weka.core.Instance;
import weka.core.Instances;

/**
 *
 * @author Ahmad Fauzan
 */
public class AODEsrReviewer implements Reviewer{
    
    final String modelPath = "aodesr-full.model";
    final String atributHeader = "header";
    Classifier cls;
    Instances dataInstances;
    List<Instance> dataSet;
    
    String cbStep = "";
    String cSession = "";
    double cDuration = 0;
    String cbCount = "";
    double ccCount = 0;
    double transact_n = 0;
    
    //Atributes
    FastVector atts;
    
    public AODEsrReviewer() {
        cls = LoadModel(modelPath);
        try { 
            SetUpAttribures(atributHeader);
        } catch (IOException ex) {
            System.out.println(ex.toString());
        }
    }

    private void SetUpAttribures(String atributHeader) throws IOException {
        System.out.println("SetUpAtributes");
        atts = new FastVector();
        InputStream is = AODEsrReviewer.class.getResourceAsStream(atributHeader);
        int c = is.read();
        String attribute = "";
        while(c > 0) {
            if(c == '\n') {
                //System.out.println(attribute);
                String[] sTemp = splitString(attribute, " ", 3);
                switch(sTemp.length) {
                    case 3 : // Adding Nominal
                        String[] sArray = sTemp[2].substring(1, sTemp[2].length()-2).split(",");
                        FastVector attributNominal = new FastVector();
                        for(int i = 0; i < sArray.length; i++) {
                            //System.out.println(sArray[i]);
                            attributNominal.addElement(sArray[i]);
                        }
                        atts.addElement(new Attribute(sTemp[1],attributNominal));
                        break;
                    case 2:
                        atts.addElement(new Attribute(sTemp[1]));
                        break;
                    default:
                        break;
                }
                attribute = "";
            }
            c = is.read();
            attribute += (char) c;
        }
        dataInstances = new Instances("DataModel", atts, 280000);
        dataInstances.setClassIndex(dataInstances.numAttributes()-1);
        
        System.out.println(dataInstances.numAttributes());
    }
    /**
     * Simple Load Model
     * @param path File Path Model
     * @return
     */
    public static Classifier LoadModel(String path) {
        try {
            InputStream is = GaIBReviewer_Ali.class.getResourceAsStream(path);
            return (Classifier) weka.core.SerializationHelper.read(is);
        } catch (Exception ex) {
            Logger.getLogger(GaIBReviewer.class.getName()).log(Level.SEVERE, null, ex);
            return null;
        }
    }
    
    public double submitTransaction(String[] transaction) {
        
        if(!cSession.equals(transaction[0])) {
            cbStep = "";
            cDuration = 0;
            cbCount = "";
            ccCount = 0;
            transact_n = 0;
        }
        
        double[] vals = new double[dataInstances.numAttributes()]; // 30 Atributes
        
        // 0 - transact_n
        transact_n += 1.0;
        vals[0] = IndexOfRangeInAtribute(dataInstances.attribute(0), 
                transact_n);
        
        cSession = transaction[0];
        
        //System.out.println();
        // 1 - avgdur
        if(transaction[3].equals("?")) {
            vals[1] = IndexOfRangeInAtribute(dataInstances.attribute(3), 0.0);
        }else {
            vals[1] = IndexOfRangeInAtribute(dataInstances.attribute(3), 
                    Double.parseDouble(transaction[3])/transact_n);
        }
        
        // 2 bStep_diff
        vals[2] = cbStep.equals(transaction[12]) ? 0.0 : 1.0;
        cbStep = transaction[12];
        
        // 3 - duration_diff - duration = ?
        vals[3] = IndexOfRangeInAtribute(dataInstances.attribute(3), 
                Double.parseDouble(transaction[3])-cDuration);
        
        // 4 - bCount_diff
        vals[4] = transaction[8].equals(cbCount) ? 0.0: 1.0;
        cbCount = transaction[8];
        
        // 5 - cCount_diff
        vals[3] = IndexOfRangeInAtribute(dataInstances.attribute(3), 
                Double.parseDouble(transaction[4])-ccCount);
        ccCount = Double.parseDouble(transaction[4]);
        
        // 6 - admisible
        if(transaction[11].equals("?") || transaction[16].equals("?")) {
            vals[6] = dataInstances.attribute(6).indexOfValue("null");
        } else {
            double t11 = Double.parseDouble(transaction[11]), 
                    t16 = Double.parseDouble(transaction[16]);
            if(t11 > t16)
                vals[6] = dataInstances.attribute(6).indexOfValue("0.0");
            else
                vals[6] = dataInstances.attribute(6).indexOfValue("1.0");
        }
        
        // 7 - startHour
        vals[7] = IndexOfRangeInAtribute(dataInstances.attribute(7), 
                Double.parseDouble(transaction[1]));
        
        // 8 - starWeekDay
        vals[8] = dataInstances.attribute(8).indexOfValue(transaction[2]);
        
        // 9 - 17
        for(int i=9; i<=17; i++) {
            if(transaction[i-6].equals("?")) {
                vals[i] = IndexOfRangeInAtribute(dataInstances.attribute(i),0.0);
            } else    
                vals[i] = IndexOfRangeInAtribute(dataInstances.attribute(i),Double.parseDouble(transaction[i-6]));
        }
        
        // 18 - 20
        for(int i = 18; i<=20; i++) {
            if(transaction[i-6].equals("?")) {
               vals[i] = dataInstances.attribute(i).indexOfValue("null");
            } else
           vals[i] = dataInstances.attribute(i).indexOfValue(transaction[i-6]);
        }
        
        // 21 customerNo
        if(transaction[15].equals("?")) {
            vals[21] = 0.0;
        } else {
            vals[21] = 1.0;
        }
        
        // 22-26
        for(int i=22; i<=26; i++) {
            if(transaction[i-6].equals("?"))
             vals[i] = IndexOfRangeInAtribute(dataInstances.attribute(i),0.0);
            else   
            vals[i] = IndexOfRangeInAtribute(dataInstances.attribute(i),Double.parseDouble(transaction[i-6]));
        }
        
        // 27
        if(transaction[21].equals("?")) {
            vals[27] = dataInstances.attribute(27).indexOfValue("null");
        } else {
            vals[27] = dataInstances.attribute(27).indexOfValue(transaction[21]+".0");
        }
        
        // 28 - lastOrder
        if(transaction[22].equals("?")) {
            vals[28] = IndexOfRangeInAtribute(dataInstances.attribute(28),0.0);
        } else {
            vals[28] = IndexOfRangeInAtribute(dataInstances.attribute(28),Double.parseDouble(transaction[22]));
        }
        // 29 - order
        vals[29] = 0.0;
        
//        for (int i =0; i < 30; i++) {
//            Attribute attr = dataInstances.attribute(i);
//            System.out.println(transaction[6]);
//            System.out.println(i);
//            String s = attr.value((int)vals[i]);
//            //System.out.print(s + ",");
//        }
        //System.out.println("");
        
        Instance data = new Instance(1.0, vals);
        data.setDataset(dataInstances);
        dataInstances.add(data);
        
        double classifyDouble=0.5;
        double[] distribution = null;
        try{
            classifyDouble = cls.classifyInstance(data);
            data.setClassValue(classifyDouble);
            distribution = cls.distributionForInstance(data);
            //System.out.println("Clasifying...");
        } catch (Exception ex) {
            //System.out.println(ex.toString());
            Logger.getLogger(GaIBReviewer.class.getName()).log(Level.SEVERE, null, ex);
        }
        
        
        //System.out.println(transaction[0] + ":" + dataInstances.attribute(2).value((int)vals[2]));
        //System.out.print(dataInstances.attribute(dataInstances.numAttributes()-1).value((int)classifyDouble) + "|");
        return (distribution[0]);
    }

    public void submitOutcome(String result) {
        //System.out.println(cls.getClass().getName());
        if(cls instanceof UpdateableClassifier) {
            for(int i =0; i < dataInstances.numInstances(); i++) {
                Instance instance = dataInstances.instance(i);
                instance.setClassValue(dataInstances.classAttribute().indexOfValue(result));
                try {
                    ((UpdateableClassifier)cls).updateClassifier(instance);
                    for(int j=0; j<30; j++) {
                        System.out.print(instance.toString(j)+"|");
                    }
                    
                    System.out.println("");
                } catch (Exception ex) {
                    System.out.println(ex.toString());
                }
            }
            //System.exit(0);
            
            
            dataInstances.delete();
            //System.out.println("Updateable");
        } else {
            //System.out.println("Not Updateable");
        }
    }
    
    /**
     * 
     * @param att Must be atribut involve the range of number
     * @param val
     * @return 
     */
    private double IndexOfRangeInAtribute(Attribute att, double val) {
        double res = 0;
        for(int i=0; i<att.numValues(); i++) {
            String s = att.value(i);
            String[] stemp = s.split("-");
            if(val< Double.parseDouble(stemp[stemp.length-1]))
                break;
            else
                res += 1.0;
        }
        return res;
    }
    
    private String[] splitString(String s, String regex, int nMax) {
        String[] sRes, sTemp = s.split(regex);
        String s_1 = "";
        if(sTemp.length > nMax) {
            sRes = new String[nMax];
            s_1 = sTemp[nMax-1];
            for(int i=nMax; i < sTemp.length; i++) {
                s_1 += " " + sTemp[i];
            }
            for(int i=0; i < nMax-1; i++) {
                sRes[i] = sTemp[i];
            }
            sRes[nMax-1] = s_1;
        } else {
            sRes = sTemp;
        }   
        return sRes;
    }
    
}
